home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / chat / reflect.000 / reflect / 3.0b3 / mbone.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-06  |  39.2 KB  |  1,415 lines

  1. /*
  2.  
  3. Copyright 1993, 1994, Cornell University
  4.  
  5. Cornell hereby grants permission to use, copy, modify, and distribute this program for any purpose 
  6. and without fee, provided that these copyright and permission notices appear on all copies and 
  7. supporting documentation, the name of Cornell not be used in advertising or publicity pertaining 
  8. to distribution of the program without specific prior permission, notice be given in supporting 
  9. documentation that copying and distribution is by permission of Cornell.  CORNELL MAKES NO 
  10. REPRESENTATIONS OR WARRANTEES, EXPRESS OR IMPLIED.  By way of example, but not limitation, 
  11. CORNELL MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR 
  12. PURPOSE OR THAT THE USE OF THIS SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, 
  13. TRADEMARKS, OR OTHER RIGHTS.  Cornell shall not be held liable for any liability with respect to 
  14. any claim by the user or any other party arising from use of the program.
  15.  
  16. This material is partially based on work sponsored by the National Science Foundation under Cooperative 
  17. Agreement No. NCR-9318337.  The government has certain rights in this material.
  18.  
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <signal.h>
  23. #include <errno.h>
  24. #include <sys/types.h>
  25. #include <sys/socket.h>
  26.  
  27. #ifndef LINUX
  28. #include <sys/socketvar.h>
  29. #endif
  30.  
  31. #include <sys/time.h>
  32. #include <netinet/in.h>
  33.  
  34. #include "reflect.h"
  35. #include "refmon.h"
  36. #include "rtp.h"
  37.  
  38. #include "globals.h"
  39.  
  40.  
  41. void mbone_pkt(msg,msglen,csock,type)
  42.    unsigned char *msg;
  43.    int msglen;
  44.    struct sockaddr_in csock;
  45.    short type;
  46. {
  47.  
  48.     struct CtrlMsgHdr   *cmhptr;
  49.     struct IDMsgHdr     *idh;
  50.     vat_client          *mcltptr,*mtmp;
  51.     client              *ctmp;
  52.     vat_hdr_t           *vat_hdr;
  53.     VideoPacketHeader   *vtmp;
  54.     unsigned char       nsid;
  55.     unsigned long       *ulptr,ul;
  56.     unsigned short      *usptr;
  57.     SiteId              *siptr;
  58.     char                *tmp,buf[50];
  59.     int                 i;
  60.     unsigned char       *cptr,*cptr1;
  61.     struct sockaddr_in  tmp1;
  62.     struct in_addr      in;
  63.     client              *nvcptr;
  64.  
  65.     switch (type)
  66.     {
  67.  
  68.        case VAT_CNTL:
  69.        case MAVEN_CNTL:
  70.  
  71.           /* check what kind of vat/maven cntrl message it is, act accordingly */ 
  72.  
  73.           cmhptr = (struct CtrlMsgHdr *) msg;
  74.  
  75.           if ((vat_confid != 0) && (ntohs(cmhptr->confid) != vat_confid)) 
  76.              return;
  77.  
  78.           switch (cmhptr->type)
  79.           {
  80.              case CTRL_TYPE_ID:
  81. #ifdef DEBUG
  82.                 if (debug)
  83.                    printf("type = CTRL_TYPE_ID\n");
  84. #endif        
  85.  
  86.                 if ((mcltptr = find_vat_client(csock.sin_addr.s_addr)) == NULL) 
  87.                 {
  88.                    if ((mcltptr = new_vat_client(csock.sin_addr.s_addr)) == NULL)
  89.                       return;
  90.         
  91.                    strncpy(mcltptr->mvn_name,cmhptr->idmsg,MAX_MAVEN_NAME_LEN);
  92.  
  93.                    mcltptr->mvn_flags = VAT_CLIENT;
  94.  
  95.                    dolog("New Maven client %s at %s\n", mcltptr->mvn_name,inet_ntoa(csock.sin_addr));
  96.  
  97.                    if (type == VAT_CNTL)
  98.                       mcltptr->mvn_recv_type = MCAST;
  99.                    else
  100.                       mcltptr->mvn_recv_type = UCAST;
  101.             
  102.                    mcltptr->mvn_idlist = NULL;
  103.       
  104.                    send_vat_idlist();
  105.                 }
  106.                 else 
  107.                    if (strncmp(mcltptr->mvn_name,cmhptr->idmsg,MAX_MAVEN_NAME_LEN)) 
  108.                    {
  109.                       strncpy(mcltptr->mvn_name,cmhptr->idmsg,MAX_MAVEN_NAME_LEN);
  110. #ifdef DEBUG
  111.                       if (debug)
  112.                          printf("Maven client at %s changing name to %s\n", inet_ntoa(csock.sin_addr),mcltptr->mvn_name);
  113. #endif
  114.                    }
  115.  
  116.                 mcltptr->mvn_rtimer = 0;
  117.                 break;
  118.  
  119.              case CTRL_TYPE_DONE:
  120. #ifdef DEBUG
  121.                 if (debug)
  122.                    printf("type = CTRL_TYPE_DONE\n");
  123. #endif
  124.                 if ((mcltptr = find_vat_client(csock.sin_addr.s_addr)) == NULL)
  125.                    return;
  126.  
  127.                 delete_vat_client(mcltptr);
  128.                 return;
  129.  
  130.              case CTRL_TYPE_IDLIST:
  131. #ifdef DEBUG
  132.                 if (debug)
  133.                    printf("type = CTRL_TYPE_IDLIST\n");
  134. #endif
  135.                 if ((mcltptr = find_vat_client(csock.sin_addr.s_addr)) == NULL) 
  136.                 {
  137.                    if ((mcltptr = new_vat_client(csock.sin_addr.s_addr)) == NULL)
  138.                       return;
  139.           
  140.                    /* 
  141.                       this is the first idlist message from this mixer, so set the speaker
  142.                       list to NULL because we haven't gotten any actual audio data yet
  143.                    */
  144.  
  145.                    dolog("New Maven client (VAT MIXER) at %s\n", inet_ntoa(csock.sin_addr));
  146.                    mcltptr->mvn_flags = VAT_MIXER;
  147.  
  148.                    if (type == VAT_CNTL)
  149.                       mcltptr->mvn_recv_type = MCAST;
  150.                    else
  151.                       mcltptr->mvn_recv_type = UCAST;
  152.  
  153.                    if ((mcltptr->mvn_idlist = (struct IDMsgHdr *) malloc(msglen)) == NULL) 
  154.                    {
  155.                       dolog("OUT OF MEMORY...ABORTING\n");
  156.                       exit(-1);
  157.                    }
  158.  
  159.                    bcopy((char *) msg, (char *) mcltptr->mvn_idlist, msglen);
  160.                    mcltptr->mvn_idlist_len = msglen;
  161.                    send_vat_idlist();
  162.                 }
  163.                 else 
  164.                 {
  165.                    /* 
  166.                       make this message the new idlist for this maven client, update the
  167.                       client's vms_head list, and then free up the old space.  This
  168.                       must be done every time because even if the idlist contains the
  169.                       same information (which may or may not be true), it may contain
  170.                       it in a different order.  Better safe than sorry. 
  171.                    */
  172.              
  173.                    mcltptr->mvn_idlist_len = msglen;
  174.  
  175.                    /* 
  176.                       idh is a temp pointer.  It points to where the new idlist is 
  177.                       put into memory.  Eventually the space pointed to by the old
  178.                       mcltptr->idlist is freed and the pointer updated to point to
  179.                       the new list 
  180.                    */
  181.  
  182.                    if ((idh = (struct IDMsgHdr *) malloc(msglen)) == NULL) 
  183.                    {
  184.                       dolog("OUT OF MEMORY...ABORTING\n");
  185.                       exit(-1);
  186.                    }
  187.           
  188.                    bcopy((char *) msg, (char *) idh, msglen);
  189.                    free((void *) mcltptr->mvn_idlist);
  190.                    mcltptr->mvn_idlist = idh;
  191.                 }
  192.                 return;
  193.    
  194.              default:
  195.                 dolog("unrecognized vat ctrl type %d \n",cmhptr->type);
  196.           }
  197.   
  198.           mcltptr->mvn_rtimer = 0;
  199.           return;
  200.           
  201.        case VAT:
  202.        case MAVEN:
  203.  
  204.           if ((mcltptr = find_vat_client(csock.sin_addr.s_addr)) == NULL)
  205.              break;
  206.  
  207.           mcltptr->mvn_rtimer = 0;
  208.  
  209.           /*
  210.              if this vat/maven packet doesn't have the right confid, then we can
  211.              just drop it.  Make sure to reset msg first! 
  212.           */
  213.  
  214.           vat_hdr = (vat_hdr_t *) msg;
  215.           
  216.           if (ntohs(vat_hdr->confid) != vat_confid)
  217.           {
  218.              dolog("Wrong vat conf_id.  Dropping packet.\n");
  219.              break;          
  220.           }
  221.           
  222.           if ((vat_hdr->nsid & NSID_MASK) == 0) 
  223.           {
  224.              /* 
  225.                 this code puts a 4-byte speaker id in after the vat header in
  226.                 order for the receiver to be able to distinguish it from the
  227.                 other streams coming from the reflector 
  228.              */
  229.         
  230.              tmp = (char *) msg;
  231.              tmp -= 4;
  232.         
  233.              bcopy((char *)msg, tmp, sizeof(vat_hdr_t));
  234.         
  235.              msg += (sizeof(vat_hdr_t) - 4);
  236.         
  237.              ulptr = (unsigned long *) msg;
  238.              *ulptr = mcltptr->mvn_addr.addr;
  239.         
  240.              msg = (unsigned char *) tmp;
  241.              
  242.              vat_hdr = (vat_hdr_t *) msg;
  243.         
  244.              /* 
  245.                 set the number of speaker id's to 1 
  246.              */
  247.  
  248.              vat_hdr->nsid = (vat_hdr->nsid & ~NSID_MASK) | 1;
  249.         
  250.              /* 
  251.                 increase the length of the packet by four bytes because we
  252.                 inserted one four-byte site_id 
  253.              */
  254.         
  255.              msglen += 4;
  256.           }
  257.           else 
  258.           {
  259.              /* 
  260.                 Ok, we've received an audio packet with a non-zero nsid field.  So
  261.                 we need to check whether this is a speaker (or speakers...note that
  262.                 this may be coming from more than one speaker at once if it is a
  263.                 true vat_mixer) who is currently on the vms list of this maven client.  
  264.                 If not, add him to the list and send an initial open continue packet.  
  265.                 If so, get on with the business of sending the packet out. 
  266.              */ 
  267.         
  268.              nsid = (vat_hdr->nsid & NSID_MASK);
  269.  
  270.              cptr = (unsigned char *) msg + sizeof(vat_hdr_t);
  271.  
  272.              for (i = 0; i < nsid; i++) 
  273.              {
  274.                 ulptr = (unsigned long *) cptr;
  275.                 sprintf(buf,"%d.%d.%d.%d\0",
  276.                         (unsigned short)*cptr,(unsigned short)*(cptr+1),(unsigned short)*(cptr+2),(unsigned short)*(cptr+3));
  277.                 ul = inet_addr(buf);
  278.  
  279.                 if ((siptr = find_site_idlist(mcltptr->mvn_idlist, *ulptr)) != NULL)
  280.                 {
  281.                    /* indicate that this person is a current speaker */
  282.                    if ((mtmp = find_vat_client(ul)) == NULL)
  283.                    {
  284.                       if ((mtmp = new_vat_client(ul)) == NULL)
  285.                          return;
  286.  
  287.                       mtmp->mvn_flags = VAT_MIXER_CLIENT;
  288.                       mtmp->mvn_pptr = mcltptr;
  289.                       strncpy(mtmp->mvn_name,siptr->id_string,MAX_MAVEN_NAME_LEN);
  290.                       dolog("New Maven client (VAT MIXER CLIENT) at %s\n", inet_ntoa(csock.sin_addr));
  291.                    }
  292.  
  293.                    if ((mtmp->mvn_spoke == 0) || ((tick_cnt - mtmp->mvn_spoke) >= VAT_SPEAKER_INTERVAL))
  294.               send_vat_ocp(mtmp);
  295.  
  296.                    mtmp->mvn_spoke = tick_cnt;
  297.                    mtmp->mvn_rtimer = 0;
  298.                 }
  299.                 else
  300.                 {
  301.                    dolog("Audio packet received with unknown speaker id.  Dropping packet.\n");
  302.                    break;
  303.                 }
  304.                 cptr += 4;
  305.              }
  306.           }
  307.  
  308.           mcltptr->mvn_rtimer = 0;
  309.           if ((mcltptr->mvn_spoke == 0) || ((tick_cnt - mcltptr->mvn_spoke) >= VAT_SPEAKER_INTERVAL))
  310.          send_vat_ocp(mcltptr);
  311.           mcltptr->mvn_spoke = tick_cnt;
  312.           mcltptr->mvn_seq++;
  313.  
  314.           if (mcltptr->mvn_talker == 0)
  315.              dolog("maven at %s is speaking\n",inet_ntoa(csock.sin_addr));
  316.  
  317.           if (mcltptr->mvn_talker++ > 50)
  318.              mcltptr->mvn_talker = 0;
  319.  
  320. #ifdef MULTI
  321.           if (((vat_out_mcast_sock) || (vat_inout_mcast_sock)) && (type != VAT)) 
  322.           {
  323.              tmp1.sin_family = AF_INET;
  324.              tmp1.sin_addr.s_addr = htonl(vat_out_mcast.sin_addr.s_addr);
  325.              tmp1.sin_port = htons(vat_port);
  326. #ifdef DEBUG
  327.              if (debug)
  328.                 printf("reflecting vat unicast pkt onto vat mcast address.\n");
  329. #endif
  330.              if (vat_inout_mcast_sock)
  331.          {
  332.                 if (sendto(vat_out_mcast_sock,msg,msglen,0,&tmp1,sizeof(struct sockaddr_in)) != msglen)
  333.                    dolog("mcast sendto error");
  334.              }
  335.          else
  336.          {
  337.                 if (sendto(vat_inout_mcast_sock,msg,msglen,0,&tmp1,sizeof(struct sockaddr_in)) != msglen)
  338.                    dolog("mcast sendto error");
  339.              }
  340.           }
  341. #endif
  342.  
  343.           mtmp = mhead;
  344.           while (mtmp != NULL) 
  345.           {
  346.              if ((mtmp != mcltptr) || (self_reflect == 1)) 
  347.              {
  348.                 if ((mtmp->mvn_recv_type == UCAST) && ((mtmp->mvn_flags & VAT_MIXER_CLIENT) == 0)) 
  349.                 {
  350.                    tmp1.sin_family = AF_INET;
  351.                    tmp1.sin_port = htons(mtmp->mvn_addr.port);
  352.                    tmp1.sin_addr.s_addr = htonl(mtmp->mvn_addr.addr);
  353. #ifdef DEBUG
  354.                    if (debug)
  355.                       printf("reflecting MAVEN pkt to ucast maven %s \n", inet_ntoa(tmp1.sin_addr));
  356. #endif
  357.                    if (sendto(maven_sock,msg,msglen,0,&tmp1,sizeof(struct sockaddr_in)) != msglen)
  358.                       dolog("maven_cntl sendto error\n");
  359.                 }
  360.              }
  361.              mtmp = mtmp->mvn_nptr;
  362.           }
  363.           
  364.           vtmp = (VideoPacketHeader *) (((unsigned char *) msg) - HEADERLEN);
  365.  
  366.           vtmp->routing.dest.family = htons(kGroup);           
  367.           vtmp->routing.dest.port = htons(VID_PORT);           
  368.           vtmp->routing.src.family = htons(kGroup);          
  369.           vtmp->routing.src.port  = htons(VID_PORT);          
  370.  
  371.           cptr = (unsigned char *) &vtmp->routing.src.addr;
  372.           cptr1 = (unsigned char *) &csock.sin_addr;
  373.           *cptr++ = *cptr1++;
  374.           *cptr++ = *cptr1++;
  375.           *cptr++ = *cptr1++;
  376.           *cptr++ = *cptr1++;
  377.  
  378.           cptr = (unsigned char *) &vtmp->seqNum;
  379.           cptr1 = (unsigned char *) &mcltptr->mvn_seq;
  380.           *cptr++ = *cptr1++;
  381.           *cptr++ = *cptr1++;
  382.           *cptr++ = *cptr1++;
  383.           *cptr++ = *cptr1++;
  384.  
  385.           vtmp->message = htons(kAudio);
  386.           vtmp->dataType = htons(kAudio);
  387.           vtmp->len = htons(msglen + HEADERLEN);
  388.  
  389.           ctmp = chead;
  390.           while (ctmp != NULL)
  391.           {
  392.              if ((ctmp->clnt_config.flags & REC_AUDIO) && (ctmp->clnt_config.flags & WANT_LURCKERS) && 
  393.                 (ctmp->clnt_flags & HOLD_DOWN) == 0)
  394. #ifdef DEBUG
  395.                 if (debug)
  396.                 {
  397.                    in.s_addr = ctmp->clnt_addr.addr;
  398.                    printf("reflecting MAVEN pkt to CUME client at %s\n",inet_ntoa(in));
  399.                 }
  400. #endif
  401.                 if (sendto(vid_sock,(char *)vtmp,msglen+HEADERLEN,0,&ctmp->clnt_addr,sizeof(struct sockaddr_in)) != msglen+HEADERLEN)
  402.                    dolog("Maven send to error in reflect\n");
  403.              ctmp = ctmp->clnt_nptr;
  404.           }
  405.           
  406.           msg = &buffer[40];
  407.  
  408.           break;
  409.  
  410.        case NV_UCAST:
  411.        case NV_MCAST:
  412.  
  413.           if ((nvcptr = find_client(csock.sin_addr.s_addr)) == NULL)
  414.           {
  415.              dolog("NV client at %s is opening a connection\n", inet_ntoa(csock.sin_addr));
  416.  
  417.              if ((nvcptr = get_client()) == NULL)
  418.              {
  419.                 dolog("unable to allocate a new nv client\n");
  420.                 return;
  421.              }
  422.          
  423.              if ((nvcptr->clnt_id = get_client_id()) == -1)
  424.              {
  425.                 dolog("maximum # of clients exceeded\n");
  426.                 return;
  427.              }
  428.  
  429.          /* 
  430.         was this new nv client also and old vat client, if so
  431.         keep the OCP sequence # space correct
  432.              */
  433.  
  434.              if ((mtmp = find_vat_client(csock.sin_addr.s_addr)) != NULL)
  435.         nvcptr->clnt_ocp_cnt = mtmp->mvn_ocp_seq;
  436.  
  437.              nvcptr->clnt_addr.family = AF_INET;
  438.              bcopy(&csock.sin_addr,&nvcptr->clnt_addr.addr,4);
  439.  
  440.              if (type == NV_UCAST)
  441.              {
  442.                 nvcptr->clnt_flags = NV_UCLIENT;
  443.                 nvcptr->clnt_addr.port = nv_ucast_port;
  444.              }
  445.              else
  446.              {
  447.                 nvcptr->clnt_flags = NV_MCLIENT;
  448.                 nvcptr->clnt_addr.port = nv_mcast_port;
  449.              }
  450.  
  451.              nvcptr->clnt_nptr = chead;
  452.              chead = nvcptr;
  453.  
  454.              nv_client_cnt++;
  455.           }
  456.  
  457.           nvcptr->clnt_bytecnt += msglen;
  458.  
  459.           nvcptr->clnt_rtimer = 0;
  460.  
  461.           distribute_nv(&msg,&msglen,nvcptr);
  462.  
  463.           if ((vtmp = nv_to_cuseeme(nvcptr,(struct rtphdr *) msg,msglen)) == NULL)
  464.           {
  465.              in.s_addr =  nvcptr->clnt_addr.addr;
  466.              dolog("Unable to convert NV encoding for %s\n",inet_ntoa(in));
  467.              delete_client(nvcptr);
  468.              return;
  469.           } 
  470.  
  471.           distribute(vtmp,nvcptr,FALSE);
  472.  
  473.           return;
  474.     }   
  475. }
  476.  
  477. /* 
  478.    takes a nv packet with an rtp (v1) header and creates (in the same buffer) a
  479.    packet with a VideoPacketHeader to transmit to cusm clients.  Note that if
  480.    the nv packet contains an RTP SDESC option (or any option, for that matter,
  481.    but SDESC is all nv sends right now) then it ignores it and just takes
  482.    care of the data.  Deals with either cusm or nv encoded video but no others. 
  483. */
  484.  
  485. VideoPacketHeader *nv_to_cuseeme(nvcltptr,rtp_hdr_ptr,msglen)
  486.      client *nvcltptr;
  487.      struct rtphdr *rtp_hdr_ptr;
  488.      int msglen;
  489. {
  490.  
  491.     struct rtcpsdeschdr *sdesc_ptr;
  492.     VideoPacketHeader   vph;
  493.     char                *cptr,*cptr1,fin;
  494.     struct rtpopthdr    *optr;
  495.     unsigned short      *usptr,cnt;
  496.  
  497.     /* move cptr to after the rtp header */
  498.     cptr = (char *) (rtp_hdr_ptr + 1);
  499.  
  500.     vph.len = msglen - sizeof(struct rtphdr) + HEADERLEN;
  501.  
  502.     /* 
  503.        if there are rtp options, move cptr to after the options.
  504.        Remember that the option length is in 4-byte words! 
  505.     */
  506.  
  507.     if (rtp_hdr_ptr->rh_opts)
  508.     {
  509.        optr = (struct rtpopthdr *) cptr;
  510.        vph.len = vph.len - optr->roh_optlen*4;
  511.  
  512.        if (optr->roh_type == RTPOPT_SDESC)
  513.        {
  514.           sdesc_ptr = (struct rtcpsdeschdr *) optr;
  515.  
  516.           cptr1 = (char *) (sdesc_ptr + 1);
  517.  
  518.           for (cnt = 0; cnt < 19; cnt++)
  519.           {
  520.              if ((nvcltptr->clnt_config.name[cnt] = *(cptr1+cnt)) == 0)
  521.                 break;
  522.  
  523.              if (nvcltptr->clnt_config.name[cnt] == '\n')
  524.                 nvcltptr->clnt_config.name[cnt] = ' ';
  525.  
  526.              if (nvcltptr->clnt_config.name[cnt] == '\r')
  527.                 nvcltptr->clnt_config.name[cnt] = ' ';
  528.           }
  529.        }
  530.  
  531.        fin = optr->roh_fin;
  532.        cptr += 4*(optr->roh_optlen);
  533.        optr = (struct rtpopthdr *) cptr;
  534.  
  535.        while (!fin) 
  536.        {
  537.           fin = optr->roh_fin;
  538.           vph.len = vph.len - optr->roh_optlen*4;
  539.           cptr += 4*(optr->roh_optlen);
  540.           optr = (struct rtpopthdr *) cptr;
  541.        } 
  542.     }
  543.  
  544.     if (rtp_hdr_ptr->rh_content == RTPCONT_NV)
  545.     {
  546.        return(NULL);
  547.     }
  548.     else
  549.        if (rtp_hdr_ptr->rh_content == RTPCONT_CELLB)
  550.        {
  551.           return(NULL);
  552.        }
  553.        else
  554.           if (rtp_hdr_ptr->rh_content != RTPCONT_CUSEEME)
  555.              return(NULL);
  556.  
  557.  
  558.     /* 
  559.        point usptr to the unsigned short type field, which we will need
  560.        to fill into the video packet header.  This two-byte field will
  561.        be kept for later, where the length of video data will be
  562.        stored before going out to cusm clients 
  563.     */
  564.  
  565.     usptr = (unsigned short *) cptr;
  566.  
  567.     /* 
  568.        move cptr to point to where the video packet header will start 
  569.     */
  570.  
  571.     cptr -= HEADERLEN;
  572.    
  573.     /* 
  574.        now fill in the video-packet header in with all the information we
  575.        presently possess. 
  576.     */
  577.  
  578.     vph.dataType = *usptr;
  579.  
  580.     if (rtp_hdr_ptr->rh_sync)
  581.        vph.message = htons(kFrameEndMessage);
  582.     else
  583.        vph.message = htons(kNoMessage);
  584.  
  585.  
  586.     nvcltptr->clnt_seq = ntohs(rtp_hdr_ptr->rh_seq);
  587.  
  588.     vph.seqNum = htonl(nvcltptr->clnt_seq + nvcltptr->clnt_ocp_cnt);
  589.  
  590.    /*
  591.       dolog("nv_to_cuseeme seq # %D\n",vph.seqNum);
  592.    */
  593.  
  594.     vph.routing.dest.port = htons(VID_PORT);
  595.     vph.routing.dest.family = htons(kGroup);
  596.     vph.routing.src.family = htons(kGroup);
  597.     vph.routing.src.port = htons(nv_mcast_port);
  598.    
  599.     /* 
  600.        usptr now points to the unsigned short after the video packet header.
  601.        this field is where nv had put the type...now we want to put in
  602.        the actual length (in bytes) of the compressed squares.  This is
  603.        equal to the length of the packet minus the header length, minus two
  604.        bytes for this field itself 
  605.     */
  606.  
  607.     *usptr = htons(vph.len - HEADERLEN - 2);
  608.  
  609.     vph.len = htons(vph.len);
  610.  
  611.     vph.routing.src.addr = htonl(nvcltptr->clnt_addr.addr);
  612.    
  613.     cptr1 = (char *) &vph;
  614.  
  615.     bcopy(cptr1,cptr,HEADERLEN);
  616.  
  617.     return((VideoPacketHeader *) cptr);
  618. }
  619.  
  620. /* 
  621.    returns a pointer to the SiteId structure which contains the given
  622.    unsigned long id.  Takes a pointer to a struct IDMsgHdr.  Returns
  623.    NULL if that id is not found.  
  624. */
  625.  
  626. SiteId *find_site_idlist(idlist,id)
  627.      struct IDMsgHdr *idlist;
  628.      unsigned long id;
  629. {
  630.     char *cptr;
  631.     SiteId *siptr;
  632.     int i,temp;
  633.   
  634.     if (idlist->nsids == 0)
  635.       return(NULL);
  636.   
  637.     cptr = (char *) idlist;
  638.     cptr += sizeof(struct IDMsgHdr);
  639.  
  640.     siptr = (SiteId *) cptr;
  641.  
  642.     for (i = 0; i < idlist->nsids; i++) 
  643.     {
  644.        if (siptr->site_id == id)
  645.          return(siptr);
  646.     
  647.        temp = strlen(siptr->id_string) + 1;
  648.     
  649.        cptr = &(siptr->id_string[temp]);
  650.     
  651.        while ((temp % 4) != 0) 
  652.        {
  653.          temp++;
  654.          cptr++;
  655.        }
  656.        siptr = (SiteId *) cptr;
  657.     }
  658.  
  659.     return(NULL);
  660. }
  661.  
  662. send_vat_ocp(mtmp)
  663.     vat_client  *mtmp;
  664. {
  665.  
  666.     VideoPacketHeader *vtmp;
  667.     client            *ctmp;
  668.  
  669.     vtmp = make_open_continue(mtmp,0,kOpenConnection,NULL);
  670.  
  671.     ctmp = chead;
  672.     while (ctmp != NULL)
  673.     {
  674.        if ((ctmp->clnt_flags & CLIENT) && ((ctmp->clnt_flags & HOLD_DOWN) == 0))
  675.        {
  676.           vtmp->routing.dest.addr = htonl(ctmp->clnt_addr.addr);
  677.           if (sendto(vid_sock,(char *)vtmp,vtmp->len,0,&ctmp->clnt_addr,sizeof(struct sockaddr_in)) != vtmp->len)
  678.              dolog("Maven send to error in reflect\n");
  679.        }
  680.        ctmp = ctmp->clnt_nptr;
  681.     }
  682. }
  683.  
  684.  
  685.  
  686. /* 
  687.    construct a generic OpenContinuePacket that will represent mptr
  688.    to the various CU-SeeMe clients.  If mptr is a vat mixer (and thus
  689.    siptr is non-NULL, use that site_id as the string to send
  690.    in the OCP.  
  691. */
  692.  
  693. VideoPacketHeader *make_open_continue(mptr,confid,message,siptr)
  694.      vat_client   *mptr;
  695.      short        confid;
  696.      short        message;
  697.      SiteId       *siptr;
  698. {
  699.   
  700.     VideoPacketHeader *vidptr;
  701.     unsigned char buffer[MAXMSG];
  702.     OpenContinueData ocd;
  703.     char *string;
  704.     unsigned char *msg = &buffer[40];
  705.  
  706.  
  707.     if (siptr != NULL) 
  708.     {
  709.        string = (char *) siptr;
  710.        string += sizeof(unsigned long);
  711.     }
  712.     else 
  713.        string = (char *) &mptr->mvn_name[0];
  714.   
  715.     
  716.     vidptr = (VideoPacketHeader *) msg;
  717.   
  718.     vidptr->conferenceid = htons(confid);
  719.     vidptr->routing.dest.family = htons(kGroup);           
  720.   
  721.     vidptr->routing.src.family = htons(kGroup);          
  722.     vidptr->routing.src.port  = htons(VID_PORT);          
  723.   
  724.     vidptr->routing.src.addr = htonl(mptr->mvn_addr.addr);
  725.                       
  726.     vidptr->seqNum = htonl(mptr->mvn_ocp_seq);
  727.  
  728.  
  729.     vidptr->message = htons(message);
  730.     vidptr->dataType = htons(kConfigVideoType);
  731.     vidptr->len = htons(HEADERLEN + sizeof(OpenContinueData));
  732.   
  733.     ocd.clientCount = 0;
  734.     ocd.seqNum = htonl(mptr->mvn_ocp_seq++);
  735.  
  736.     /*
  737.     dolog("make_open_continue seq # %D\n",vidptr->seqNum);
  738.     */
  739.  
  740.     msg = (unsigned char *) ocd.name;
  741.     if (strlen(string) > 19)
  742.        *msg++ = 19;
  743.     else
  744.        *msg++ = strlen(string);
  745.  
  746.     strncpy((char *) msg,string,19);
  747.   
  748.     ocd.sendMode = 0;
  749.     ocd.recvMode = 0;
  750.     ocd.flags = REC_AUDIO | AUDIO_CAPABLE | WANT_LURCKERS;
  751.     ocd.version = NV_CLIENT_VERS;
  752.   
  753.     msg = (unsigned char *) vidptr;
  754.   
  755.     /* 
  756.        This gets rid of the padding put between the first two members of ocd 
  757.     */
  758.  
  759.     bcopy((char *) &ocd.seqNum,(char *) &ocd.clientCount + sizeof(ocd.clientCount),sizeof(ocd));
  760.   
  761.     msg += HEADERLEN;
  762.   
  763.     bcopy((char *) &ocd, (char *) msg, sizeof(OpenContinueData));
  764.   
  765.     return(vidptr);  
  766. }
  767.  
  768. void delete_vat_client(mptr)
  769.     vat_client *mptr;
  770. {
  771.  
  772.     vat_client *mtmp1;
  773.     struct in_addr in;
  774.  
  775.     in.s_addr =  mptr->mvn_addr.addr;
  776.  
  777.     dolog("Deleting Maven client at %s\n", inet_ntoa(in));
  778.  
  779.     if (mptr == mhead)
  780.     {
  781.        mhead = mptr->mvn_nptr;
  782.        mtmp1 = mptr;
  783.        mptr = mptr->mvn_nptr;
  784.        free(mtmp1);
  785.     }
  786.     else
  787.     {
  788.        mtmp1 = mhead;
  789.        while (mtmp1->mvn_nptr != mptr)
  790.           mtmp1 = mtmp1->mvn_nptr;
  791.        mtmp1->mvn_nptr = mptr->mvn_nptr;
  792.        mtmp1 = mptr;
  793.        mptr = mptr->mvn_nptr;
  794.        free(mtmp1);
  795.     }
  796.     vat_client_cnt--;
  797. }
  798.  
  799. vat_client *new_vat_client(caddr)
  800.     unsigned long caddr;
  801. {
  802.     vat_client *ctmp;
  803.  
  804.     if ((ctmp = (vat_client *) calloc(1,sizeof(vat_client))) == NULL)
  805.        return(NULL);
  806.  
  807.     ctmp->mvn_addr.addr = caddr;
  808.     ctmp->mvn_addr.port = maven_port;
  809.     ctmp->mvn_addr.family = AF_INET;
  810.  
  811.     ctmp->mvn_nptr = mhead;
  812.     mhead = ctmp;
  813.     vat_client_cnt++;
  814.  
  815.     return(ctmp);
  816. }
  817.  
  818. char num_vat_clients(type)
  819.    char type;
  820. {
  821.     vat_client *mptr;
  822.     char num;
  823.  
  824.     mptr = mhead;
  825.     num = 0;
  826.  
  827.     while (mptr != NULL)
  828.     {
  829.        if (mptr->mvn_recv_type == type)
  830.           num++;
  831.        mptr = mptr->mvn_nptr;
  832.     }
  833.     return(num);
  834. }
  835.  
  836.  
  837.  
  838. void vat_id(mptr)
  839.     vat_client *mptr;
  840. {
  841.     static char         buf[MAXMSG];
  842.     struct CtrlMsgHdr   *vatIdmsg;
  843.     int                 msglen;
  844.     struct in_addr      in;
  845.     struct sockaddr_in  mvnskt;
  846.  
  847. #ifdef DEBUG
  848.     if (debug)
  849.     {
  850.        in.s_addr = mptr->mvn_addr.addr;
  851.        printf("sending id message to maven at %s\n",inet_ntoa(in));
  852.     }
  853. #endif
  854.  
  855.     vatIdmsg = (struct CtrlMsgHdr *) buf;
  856.     vatIdmsg->flags = 0;
  857.     vatIdmsg->type = CTRL_TYPE_ID;
  858.     vatIdmsg->confid = 0;
  859.     strcpy(vatIdmsg->idmsg,"CU-Reflector");
  860.     vatIdmsg->idmsg[strlen("CU-Reflector")] = 0;
  861.     msglen = CTRLMSGSIZE + strlen("CU-Reflector") + 1;
  862.  
  863.     mvnskt.sin_family = AF_INET;
  864.     mvnskt.sin_port = mptr->mvn_addr.port + 1;
  865.     mvnskt.sin_addr.s_addr = mptr->mvn_addr.addr;
  866.  
  867.     pkts_out++;
  868.     bytes_out += msglen;
  869.  
  870.     if (sendto(maven_cntl_sock_out,buf,msglen,0,&mvnskt,sizeof(struct sockaddr_in)) != msglen)
  871.        dolog("Maven id sendto error\n");
  872.  
  873. }
  874.  
  875.  
  876. /* 
  877.    constructs and sends a vat CTRL_TYPE_IDLIST message to all vat and
  878.    maven clients.  The function takes care of sending the appropriate
  879.    message to the mcast address and to the ucast vat/mavens that
  880.    are connected... note that these are usually different.  
  881. */
  882.  
  883. void send_vat_idlist()
  884. {
  885.     vat_client           *mptr,*mptr1;
  886.     char                 buffer[MAXMSG],*cptr,temp;
  887.     client               *cltptr;
  888.     struct IDMsgHdr      *idhptr;
  889.     SiteId               *sidptr;
  890.     int                  msglen,i;
  891.     struct sockaddr_in   tmp1;
  892.     char                 num_mcast,num_ucast,count;
  893.  
  894.     num_mcast = num_vat_clients(MCAST);
  895.     num_ucast = num_vat_clients(UCAST);
  896.  
  897.     mptr = mhead;
  898.  
  899.     cptr = buffer + 40 + sizeof(struct IDMsgHdr);
  900.  
  901.     sidptr = (SiteId *) cptr;
  902.     count = 0;
  903.  
  904.     /* 
  905.        construct the idlist that represents all ucast mavens to the mcast
  906.        vats.  If there are no ucast maven/vats and no cusm clients, send nothing  
  907.     */
  908.  
  909.     if (vat_out_mcast.sin_addr.s_addr)
  910.     {
  911.        while (mptr != NULL) 
  912.        {
  913.           if (mptr->mvn_recv_type == UCAST)
  914.           {
  915.              if (mptr->mvn_idlist == NULL)
  916.              {
  917.                 sidptr->site_id = mptr->mvn_addr.addr;
  918.                 strcpy(sidptr->id_string,mptr->mvn_name);
  919.    
  920.                 temp = strlen(sidptr->id_string) + 1;
  921.    
  922.                 cptr = &(sidptr->id_string[temp]);
  923.    
  924.                 while ((temp % 4) != 0) 
  925.                 {
  926.                    temp++;
  927.                    cptr++;
  928.                 }
  929.                 sidptr = (SiteId *) cptr;
  930.              }
  931.              else 
  932.              {
  933.                 /* 
  934.                    copy the idlist that this maven client has been sending (see reflect.c)
  935.                    into the idlist we are presently building.  mptr->idlist points to a
  936.                    struct IDMsgHdr, which we don't want, so skip over it. 
  937.                 */
  938.    
  939.                 count += mptr->mvn_idlist->nsids;
  940.    
  941.                 cptr = (char *) mptr->mvn_idlist;
  942.                 cptr += sizeof(struct IDMsgHdr);
  943.                 temp = mptr->mvn_idlist_len - sizeof(struct IDMsgHdr);
  944.    
  945.                 bcopy(cptr, (char *) sidptr, temp);
  946.                 cptr = (char *) sidptr;
  947.                 cptr += temp;
  948.    
  949.                 while ((temp % 4) != 0) 
  950.                 {
  951.                    temp++;
  952.                    cptr++;
  953.                 }
  954.    
  955.                 sidptr = (SiteId *) cptr;
  956.    
  957.              }
  958.           }
  959.           mptr = mptr->mvn_nptr;
  960.        }
  961.    
  962.        cltptr = chead;
  963.        while (cltptr != NULL) 
  964.        {
  965.           if (cltptr->clnt_config.flags & AUDIO_CAPABLE) 
  966.           {
  967.              count++;
  968.    
  969.              sidptr->site_id = cltptr->clnt_addr.addr;
  970.              strncpy(sidptr->id_string,cltptr->clnt_config.name,20);
  971.    
  972.              temp = strlen(sidptr->id_string) + 1;
  973.              cptr = &(sidptr->id_string[temp]);
  974.    
  975.              while ((temp % 4) != 0) 
  976.              {
  977.                 temp++;
  978.                 cptr++;
  979.              }
  980.    
  981.              sidptr = (SiteId *) cptr;
  982.           }
  983.    
  984.           cltptr = cltptr->clnt_nptr;
  985.        }
  986.  
  987.        count++;
  988.   
  989.        sidptr->site_id = myaddr.sin_addr.s_addr;
  990.        strncpy(sidptr->id_string,"CU-Reflector        ",20);
  991.  
  992.        temp = strlen("CU-Reflector") + 1;
  993.        cptr = &(sidptr->id_string[temp]);
  994.  
  995.        while ((temp % 4) != 0)
  996.        {
  997.           temp++;
  998.           cptr++;
  999.        }
  1000.  
  1001.        idhptr = (struct IDMsgHdr *) &buffer[40];
  1002.        idhptr->flags = 0;
  1003.        idhptr->type = CTRL_TYPE_IDLIST;
  1004.        idhptr->confid = htons(vat_confid);
  1005.        idhptr->nsids = num_ucast + count;
  1006.        idhptr->ainfo = 0;
  1007.        idhptr->blksize = 0;
  1008.  
  1009.        msglen = cptr - &buffer[40];
  1010.        cptr = &buffer[40];
  1011.  
  1012.        tmp1.sin_family = AF_INET;
  1013.        tmp1.sin_addr.s_addr = htonl(vat_out_mcast.sin_addr.s_addr);
  1014.        tmp1.sin_port = htons(vat_port + 1);
  1015.  
  1016. #ifdef DEBUG
  1017.        if (debug)
  1018.           printf("Sending Idlist of UCAST mavens to mcast address \n");
  1019. #endif
  1020.        if (sendto(vat_cntl_mcast_sock,cptr,msglen,0,&tmp1,sizeof(struct sockaddr_in)) != msglen)
  1021.           dolog("mcast sendto error");
  1022.     }
  1023.  
  1024.     /* 
  1025.        construct the idlist to send to ucast maven/vat clients.  Do not send one if there is
  1026.        one or zero clients.  (vat_id() takes care of 1, and obviously if there are no
  1027.        clients then we don't want to send anything... 
  1028.     */
  1029.  
  1030.     if ((mptr = mhead) == NULL)
  1031.        return;
  1032.  
  1033.     if ((mptr->mvn_nptr == NULL) && (chead == NULL))
  1034.        vat_id(mptr);
  1035.  
  1036.     cptr = buffer + 40 + sizeof(struct IDMsgHdr);
  1037.  
  1038.     sidptr = (SiteId *) cptr;
  1039.  
  1040.     count = 0;
  1041.  
  1042.     while (mptr != NULL) 
  1043.     {
  1044.        if (mptr->mvn_idlist == NULL)
  1045.        {
  1046.           sidptr->site_id = mptr->mvn_addr.addr;
  1047.           strcpy(sidptr->id_string,mptr->mvn_name);
  1048.  
  1049.           temp = strlen(sidptr->id_string) + 1;
  1050.  
  1051.           cptr = &(sidptr->id_string[temp]);
  1052.  
  1053.           while ((temp % 4) != 0) 
  1054.           {
  1055.              temp++;
  1056.              cptr++;
  1057.           }
  1058.  
  1059.           sidptr = (SiteId *) cptr;
  1060.        }
  1061.        else 
  1062.        {
  1063.           /* 
  1064.              copy the idlist that this maven client has been sending (see reflect.c)
  1065.              into the idlist we are presently building.  mptr->mvn_idlist points to a
  1066.              struct IDMsgHdr, which we don't want, so skip over it. 
  1067.           */
  1068.  
  1069.           count += mptr->mvn_idlist->nsids;
  1070.  
  1071.           cptr = (char *) mptr->mvn_idlist;
  1072.           cptr += sizeof(struct IDMsgHdr);
  1073.           temp = mptr->mvn_idlist_len - sizeof(struct IDMsgHdr);
  1074.  
  1075.           bcopy(cptr, (char *) sidptr, temp);
  1076.           cptr = (char *) sidptr;
  1077.           cptr += temp;
  1078.  
  1079.           while ((temp % 4) != 0) 
  1080.           {
  1081.              temp++;
  1082.              cptr++;
  1083.           }
  1084.  
  1085.           sidptr = (SiteId *) cptr;
  1086.        }
  1087.        mptr = mptr->mvn_nptr;
  1088.     }
  1089.  
  1090.     cltptr = chead;
  1091.     while (cltptr != NULL) 
  1092.     {
  1093.        if (cltptr->clnt_config.flags & AUDIO_CAPABLE) 
  1094.        {
  1095.           count++;
  1096.  
  1097.           sidptr->site_id = cltptr->clnt_addr.addr;
  1098.           strncpy(sidptr->id_string,cltptr->clnt_config.name,20);
  1099.  
  1100.           temp = strlen(sidptr->id_string) + 1;
  1101.           cptr = &(sidptr->id_string[temp]);
  1102.  
  1103.           while ((temp % 4) != 0) 
  1104.           {
  1105.              temp++;
  1106.              cptr++;
  1107.           }
  1108.  
  1109.           sidptr = (SiteId *) cptr;
  1110.        }
  1111.        cltptr = cltptr->clnt_nptr;
  1112.     }
  1113.  
  1114.     count++;
  1115.   
  1116.     sidptr->site_id = myaddr.sin_addr.s_addr;
  1117.     strncpy(sidptr->id_string,"CU-Reflector        ",20);
  1118.  
  1119.     temp = strlen("CU-Reflector") + 1;
  1120.     cptr = &(sidptr->id_string[temp]);
  1121.  
  1122.     while ((temp % 4) != 0)
  1123.     {
  1124.        temp++;
  1125.        cptr++;
  1126.     }
  1127.  
  1128.     idhptr = (struct IDMsgHdr *) &buffer[40];
  1129.     idhptr->flags = 0;
  1130.     idhptr->type = CTRL_TYPE_IDLIST;
  1131.     idhptr->confid = htons(vat_confid);
  1132.     idhptr->nsids = num_ucast + num_mcast + count;
  1133.     idhptr->ainfo = 0;
  1134.     idhptr->blksize = 0;
  1135.  
  1136.     msglen = cptr - &buffer[40];
  1137.     cptr = &buffer[40];
  1138.  
  1139.     mptr = mhead;
  1140.  
  1141.     while (mptr != NULL) 
  1142.     {
  1143.        if (mptr->mvn_recv_type == UCAST)
  1144.        {
  1145.           tmp1.sin_family = AF_INET;
  1146.           tmp1.sin_addr.s_addr = htonl(mptr->mvn_addr.addr);
  1147.           tmp1.sin_port = htons(maven_port + 1);
  1148.  
  1149.           dolog("Sending Idlist of %d clients to UCAST maven %s \n",count, inet_ntoa(tmp1.sin_addr));
  1150.  
  1151.           if (sendto(maven_cntl_sock_out,cptr,msglen,0,&tmp1,sizeof(struct sockaddr_in)) != msglen)
  1152.              dolog("maven_cntl_sock_out sendto error");
  1153.        }
  1154.        mptr = mptr->mvn_nptr;
  1155.     }
  1156. }
  1157.  
  1158.  
  1159. void send_nv_ocp(nvcltptr)
  1160.      client *nvcltptr; 
  1161. {
  1162.  
  1163.     VideoPacketHeader *vidptr;
  1164.     client *ctmp;
  1165.     short audio = 0;
  1166.  
  1167.     unsigned char buffer[MAXMSG];
  1168.     unsigned char *msg = &buffer[40],*cptr;
  1169.  
  1170.     vidptr = (VideoPacketHeader *) msg;
  1171.  
  1172.     vidptr->conferenceid = conference_id;
  1173.  
  1174.     vidptr->routing.dest.family = htons(kReflector);
  1175.  
  1176.     bcopy(&myaddr.sin_addr.s_addr,&vidptr->routing.dest.addr,4);
  1177.  
  1178.     vidptr->routing.src.family = htons(kClient);
  1179.     vidptr->routing.src.port  = htons(VID_PORT);
  1180.  
  1181.     bcopy(&nvcltptr->clnt_addr.addr,&vidptr->routing.src.addr,4);
  1182.  
  1183.     vidptr->seqNum = htonl(nvcltptr->clnt_seq + ++nvcltptr->clnt_ocp_cnt);
  1184.  
  1185.     /*
  1186.     dolog("send_nv_ocp seq # %D\n",vidptr->seqNum);
  1187.     */
  1188.  
  1189.     vidptr->message = htons(kOpenConnection);
  1190.     vidptr->dataType = htons(kConfigVideoType);
  1191.     vidptr->len = htons(HEADERLEN + OCDLEN);
  1192.  
  1193.     cptr = (unsigned char *) ((unsigned char *) vidptr + HEADERLEN);
  1194.  
  1195.     bcopy(&client_cnt,cptr,2);
  1196.     cptr += 2;
  1197.  
  1198.     bcopy(&nvcltptr->clnt_ocp_cnt,cptr,4);
  1199.     cptr += 4;
  1200.  
  1201.     *cptr++ = strlen(nvcltptr->clnt_config.name);
  1202.  
  1203.     strncpy(cptr,nvcltptr->clnt_config.name,19);
  1204.  
  1205.     cptr += 19;
  1206.  
  1207.     *cptr++ = 1;
  1208.     *cptr++ = 1;
  1209.  
  1210.     if (find_vat_client(nvcltptr->clnt_addr.addr) != NULL)
  1211.     {
  1212.        *cptr++ = REC_AUDIO | AUDIO_CAPABLE | WANT_LURCKERS;
  1213.        audio = 1;
  1214.     }
  1215.     else
  1216.        *cptr++ = 0;
  1217.  
  1218.     *cptr++ = NV_CLIENT_VERS;
  1219.  
  1220.     msg += HEADERLEN + OCDLEN;
  1221.  
  1222.     ctmp = chead;
  1223.     while (ctmp != NULL)
  1224.     {
  1225.        if (ctmp->clnt_flags & CLIENT)
  1226.        {
  1227.           bcopy(&ctmp->clnt_addr.addr,msg,4);
  1228.           msg += 4;
  1229.           if (audio)
  1230.              *msg++ = IWillRecAudio;
  1231.           else
  1232.              *msg++ = 0;
  1233.  
  1234.           *msg++ = 0;
  1235.           *msg++ = 1;
  1236.           *msg++ = 1;
  1237.           msg += 4;
  1238.           vidptr->len += 12;
  1239.        }
  1240.        ctmp = ctmp->clnt_nptr;
  1241.     }
  1242.     
  1243.     ctmp = chead;
  1244.     while (ctmp != NULL) 
  1245.     {
  1246.        if ((ctmp->clnt_flags & (CLIENT | BCC_CLIENT)) && (ctmp->clnt_flags & HOLD_DOWN) == 0)
  1247.        {
  1248.           vidptr->routing.dest.addr = htonl(ctmp->clnt_addr.addr);
  1249.  
  1250.           if (sendto(vid_sock,(char *)vidptr,vidptr->len,0,&ctmp->clnt_addr,sizeof(struct sockaddr_in)) != vidptr->len)
  1251.              dolog("NV send to error in reflect\n");
  1252.        }
  1253.  
  1254.        ctmp = ctmp->clnt_nptr;
  1255.     }
  1256.  
  1257. }
  1258.  
  1259. vat_client *find_vat_client(caddr)
  1260.     unsigned long caddr;
  1261. {
  1262.     vat_client *ctmp;
  1263.  
  1264.     ctmp = mhead;
  1265.  
  1266.     while (ctmp != NULL)
  1267.     {
  1268.       if (ctmp->mvn_addr.addr == caddr)
  1269.          return(ctmp);
  1270.       ctmp = ctmp->mvn_nptr;
  1271.     }
  1272.     return(NULL);
  1273. }
  1274.  
  1275. nv_wrt(srcptr,vidptr)
  1276.     client              *srcptr;
  1277.     VideoPacketHeader   *vidptr;
  1278. {
  1279.     client *ctmp;
  1280.     unsigned char *cptr,*tmp;
  1281.     unsigned char id;
  1282.     unsigned short datatype,seqnum,message,client_id;
  1283.     unsigned long timestamp,ltmp;
  1284.     struct in_addr in;
  1285.     short len,wlen,err;
  1286.  
  1287.     cptr = ((unsigned char *) vidptr) + HEADERLEN;
  1288.  
  1289.     datatype = vidptr->dataType;
  1290.     bcopy(&datatype,cptr,sizeof(datatype));
  1291.  
  1292.     client_id = htons(srcptr->clnt_id);
  1293.  
  1294.     bcopy(&vidptr->seqNum,<mp,4);
  1295.     seqnum = ltmp;                             /* truncate to 16 bits for RTP header */
  1296.  
  1297.     message = ntohs(vidptr->message);
  1298.     len = ntohs(vidptr->len) - HEADERLEN + MHEADERLEN + SSRCLEN;
  1299.  
  1300.     timestamp = RTPTime();
  1301.     if (((timestamp - srcptr->clnt_sdesc_time) >> 16) >= NV_SDESC_TIMER)
  1302.     {
  1303.        srcptr->clnt_sdesc_time = timestamp;
  1304.  
  1305.        wlen = (strlen(srcptr->clnt_config.name) >> 2) + 3;
  1306.        cptr -= (wlen << 2);
  1307.  
  1308.        tmp = cptr;
  1309.        *tmp++ = SDESC | FINAL;                           /* RTP SDESC option is FINAL option */
  1310.        *tmp++ = wlen;                                    /* option length */
  1311.        *((unsigned short *) tmp) = client_id;            /* client id */
  1312.        tmp += sizeof(client_id);
  1313.        bcopy(&srcptr->clnt_addr.addr,tmp,sizeof(struct in_addr));
  1314.  
  1315.        /* client addr */
  1316.        tmp += sizeof(struct in_addr);
  1317.        strcpy(tmp,srcptr->clnt_config.name);             /* client name */
  1318.  
  1319.        *(cptr - SSRCLEN) = SSRC;                         /* RTP SSRC option */
  1320.     }
  1321.     else
  1322.     {
  1323.        wlen = 0;
  1324.        *(cptr - SSRCLEN) = SSRC | FINAL;  /* RTP SSRC option is FINAL option */
  1325.     }
  1326.  
  1327.     len += (wlen << 2);
  1328.  
  1329.     cptr -= MHEADERLEN + SSRCLEN;
  1330.     tmp = cptr;
  1331.  
  1332.     /* start of RTP header */
  1333.  
  1334.     /*
  1335.     *tmp++ = NVVERSION | client_id;                        /* nv version & channel id */
  1336.     
  1337.  
  1338.     *tmp++ = NVVERSION | NV_CHAN;                        /* nv version & channel id */
  1339.  
  1340.     *tmp = NVCONTENT | NVOBIT;                           /* nv content with RTP options */
  1341.  
  1342.     if (message == kFrameEndMessage)
  1343.        *tmp |= NVSBIT;                                   /* nv framing bit */
  1344.  
  1345.     tmp++;
  1346.  
  1347.     *((unsigned short *) tmp) = seqnum;                  /* seq */
  1348.     tmp += sizeof(seqnum);
  1349.     timestamp = htonl(timestamp);
  1350.     bcopy(×tamp,tmp,sizeof(timestamp));
  1351.     tmp += sizeof(timestamp) + 1;
  1352.  
  1353.     /* RTP SSRC option */
  1354.     /* already set RTP option type */
  1355.  
  1356.     *tmp++ = SSRCLEN >> 2;                               /* RTP option length */
  1357.     *((unsigned short *) tmp) = client_id;               /* client id */
  1358.     tmp += sizeof(client_id);
  1359.     bcopy(&srcptr->clnt_addr.addr,tmp,sizeof(struct in_addr)); /* client addr */
  1360.  
  1361.     if (send_to_nv(srcptr))
  1362.     {
  1363.        ctmp = chead;
  1364.        while (ctmp != NULL)
  1365.        {
  1366.           if (ctmp->clnt_flags & NV_UCLIENT)
  1367.              if (err = (sendto(nv_ucast_sock,cptr,len,0,&ctmp->clnt_addr,sizeof(struct sockaddr_in))) != len)
  1368.                 dolog("nv ucast sendto error %d\n",err);
  1369.  
  1370.           ctmp = ctmp->clnt_nptr;
  1371.        }
  1372.     }
  1373.  
  1374.     if (nv_out_mcast_sock)
  1375.        if (err = (sendto(nv_out_mcast_sock,cptr,len,0,&nv_out_mcast,sizeof(struct sockaddr_in))) != len)
  1376.           dolog("nv mcast sendto error %d on nv_out_mcast_sock\n",err);
  1377.  
  1378.     if (nv_inout_mcast_sock)
  1379.        if (err = (sendto(nv_inout_mcast_sock,cptr,len,0,&nv_inout_mcast,sizeof(struct sockaddr_in))) != len)
  1380.           dolog("nv mcast sendto error %d\n on nv_inout_mcast_sock",err);
  1381. }
  1382.  
  1383. unsigned long RTPTime()
  1384. {
  1385.     struct timeval t;
  1386.  
  1387.     gettimeofday(&t, NULL);
  1388.     return ((t.tv_sec + RTP_EPOCH_OFFSET) << 16) | ((t.tv_usec << 10) / 15625);
  1389. }
  1390.  
  1391. short send_to_nv(cltptr)
  1392.     client *cltptr;
  1393. {
  1394.     short cnt;
  1395.  
  1396.     if (nv_client_cnt == 0)
  1397.        return(0);
  1398.  
  1399.     for (cnt=0; cnt<send_to_nv_cnt; cnt++)
  1400.        if (send_to_nv_list[cnt] == cltptr->clnt_addr.addr)
  1401.        {
  1402.           send_to_nv_timer[cnt] = 0;
  1403.           return(1);
  1404.        }
  1405.     
  1406.     if (send_to_nv_cnt < nv_streams)
  1407.     {
  1408.        send_to_nv_list[send_to_nv_cnt] = cltptr->clnt_addr.addr;
  1409.        send_to_nv_timer[cnt] = 0;
  1410.        send_to_nv_cnt++;
  1411.        return(1);
  1412.     }
  1413.     return(0);
  1414. }
  1415.